use std::ffi::NulError;
use std::fmt::format;
use crate::resp::{BulkString, RespArray, RespMap, RespNull, RespNullBulkString, RespSet, RespSimpleError, RespSimpleString};
use crate::{RespEncode, RespFrame};
use crate::RespFrame::SimpleString;

const ARRAY_CAP:usize = 4096;
// - simple string:  "+OK\r\n"
impl RespEncode for RespSimpleString {
    fn encode(self) -> Vec<u8> {
        format!("+{}\r\n",self).into_bytes()
    }
}

// - integer: ":[<+|-><value>\r\n"
impl RespEncode for i64 {
    fn encode(self) -> Vec<u8> {
        let sign = if self <0 {"-"} else {"+"};
        format!(":{}{}\r\n",sign,self).into_bytes()
    }
}

//- error: "-Error message\r\n"
impl RespEncode for RespSimpleError {
    fn encode(self) -> Vec<u8> {
        format!("-{}\r\n",self).into_bytes()
    }
}

//-bulk string: "$<length>\r\n<data>\r\n"

impl  RespEncode for BulkString {
    fn encode(self) -> Vec<u8> {
        let mut buf = Vec::with_capacity(self.len()+16);
        buf.extend_from_slice(&format!("${}\r\n",self.len()).into_bytes());
        buf.extend_from_slice(&self);
        buf.extend_from_slice(b"\r\n");
        buf
    }
}

//- null bulk: "$-1\r\n"
impl RespEncode for RespNullBulkString {
    fn encode(self) -> Vec<u8> {
        b"$-1\r\n".to_vec()
    }
}
// - null: "_\r\n"
impl RespEncode for RespNull {
    fn encode(self) -> Vec<u8> {
        b"_\r\n".to_vec()
    }
}

// - boolean: "#<t|f>\r\n"
impl RespEncode for bool {
    fn encode(self) -> Vec<u8> {
        let result = if self {"t"} else {"f"};
        format!("#{}\r\n",result).into_bytes()
    }
}

impl RespEncode for RespFrame {
    fn encode(self) -> Vec<u8> {
        todo!()
    }
}

// - array: "*<number-of-elements>\r\n<element-1>...<element-n>"

impl RespEncode for RespArray {
    fn encode(self) -> Vec<u8> {

        let mut buf =Vec::with_capacity(ARRAY_CAP);
        buf.extend_from_slice(&format!("*{}\r\n",self.0.len()).into_bytes());
        for frame in self.0 {
            buf.extend_from_slice(&frame.encode());
        }
        buf
    }
}

//- double: ",[<+|->]<integral>[.<fractioal>]" ...
impl RespEncode for f64  {
    fn encode(self) -> Vec<u8> {
        let mut buf = Vec::with_capacity(32);
        buf.extend_from_slice(&format!(",{:+e}\r\n",self).into_bytes());

        buf
    }
}

// - map: "%<number-of-entries>\r\n<key-1><value1>...<key-n><value-n>"

impl RespEncode for RespMap {
    fn encode(self) -> Vec<u8> {
       let mut buf = Vec::with_capacity(ARRAY_CAP);
        buf.extend_from_slice(&format!("%{}\r\n",self.0.len()).into_bytes());
        for ( key,value) in self.0 {
            buf.extend_from_slice(&RespSimpleString::new(key).encode());
            buf.extend_from_slice(&value.encode());
        }
        buf
    }
}

// set: "~<number-of-elements>\r\n<element-1>...<element-n>"
impl RespEncode for RespSet {
    fn encode(self) -> Vec<u8> {
        let mut buf = Vec::with_capacity(ARRAY_CAP);
        buf.extend_from_slice(&format!("~{}\r\n",self.0.len()).into_bytes());
        for frame in self.0 {
            buf.extend_from_slice(&frame.encode());
        }
        buf
    }
}


#[cfg(test)]
mod tests {
    use super::*;

}